package com.bobexchen.nettywebsocket.manager;

import com.alibaba.fastjson.JSON;
import com.bobexchen.nettywebsocket.common.ConstantVal;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Service
public class NettyChannelManager {

    private Logger log = LoggerFactory.getLogger(getClass());
    /**
     * Channel映射
     */
    private ConcurrentMap<ChannelId, Channel> channels = new ConcurrentHashMap<>();

    /**
     * 用户与Channel的映射。
     * <p>
     * 通过它，可以获取用户对应的Channel。这样，我们可以向指定用户发送消息。
     */
    private ConcurrentMap<String, Channel> userChannels = new ConcurrentHashMap<>();


    /**
     * @paramchannel
     */
    public void add(Channel channel) {
        channels.put(channel.id(), channel);
        log.info("[add][一个连接({})加入]", channel.id());
    }

    /**
     * 添加指定用户到{@link#userChannels}中
     *
     * @paramchannelChannel
     * @paramuid用户
     */
    public void addUser(Channel channel, String uid) {
        log.info("addUserstart");
        if (channel.hasAttr(ConstantVal.CHANNEL_ATTR_KEY_USER)) {
            log.info("已存在");
            return;
        }

        if (!Objects.isNull(userChannels.get(uid))) {
            log.info("当前用户已存在");
            channels.remove(channel.id());
            return;
        }

        Channel existChannel = channels.get(channel.id());
        if (existChannel == null) {
            log.error("[addUser][连接({})不存在]", channel.id());
            return;
        }
        //设置属性
        channel.attr(ConstantVal.CHANNEL_ATTR_KEY_USER).set(uid);
        //添加到userChannels
        log.info("[addUser][一个用户{}加入]", uid);
        userChannels.put(uid, channel);
        log.info("userChannelsis{}", userChannels);
    }

    /**
     * 将Channel从{@link#channels}和{@link#userChannels}中移除
     *
     * @paramchannelChannel
     */
    public void remove(Channel channel) {

        if (channel.hasAttr(ConstantVal.CHANNEL_ATTR_KEY_USER)) {
            String user = (String) channel.attr(ConstantVal.CHANNEL_ATTR_KEY_USER).get();
            if (user != null) {
                //移除userChannels
                log.info("[remove][一个用户（{}）连接({})离开]", user, channel.id());
                userChannels.remove(user);
            }
        }

        //移除channels
        channels.remove(channel.id());
    }

    /**
     * 向指定用户发送消息
     *
     * @paramtoUser用户
     * @paramnormalMessage消息体
     */
    public void send(String toUser, String normalMessage) {
        //获得用户对应的Channel
        Channel channel = userChannels.get(toUser);
        if (channel == null) {
            log.error("[send][{}连接不存在]", toUser);
            return;
        }
        if (!channel.isActive()) {
            log.error("[send][连接({})未激活]", channel.id());
            return;
        }
        //发送消息
        String jsonString = JSON.toJSONString(normalMessage);
        log.info("连接【{}】【{}】发送消息：【{}】", channel.attr(ConstantVal.CHANNEL_ATTR_KEY_USER).get(), channel.id().toString(), jsonString);
        channel.writeAndFlush(new TextWebSocketFrame(jsonString));
    }

}
